﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyCollection
{
	public class Queue<T>
	{
		#region Properties

		/// <summary>
		/// The capacity of the Elements Collection
		/// </summary>
		private int _capacity;
		public int Capacity
		{
			get { return _capacity; }
			set { _capacity = value; }
		}

		/// <summary>
		/// The number of elements currently in the queue.
		/// </summary>

		public int Length
		{
			get;
			set;
		}


		/// <summary>
		/// The actual data elements stored in the queue.
		/// </summary>
		protected T[] Elements
		{
			get;
			set;
		}

		/// <summary>
		/// This is the index where we will dequeue.
		/// </summary>
		public int FrontIndex
		{
			get;
			set;
		}

		/// <summary>
		/// This is the index where we will next enqueue a value. 
		/// It is calculated based on the Front Index, Length, and Capacity
		/// </summary>
		public int BackIndex
		{
			get { return (FrontIndex + Length) % Capacity; }
		}

		#endregion


		public Queue()
		{
			Elements = new T[2];
		}

		public Queue(int capacity)
		{
			Capacity = capacity;
			Elements = new T[Capacity];
		}

		public void Enqueue(T element)
		{
			if (this.Length == Capacity)
			{
				IncreaseCapacity();
			}
			Elements[BackIndex] = element;
			Length++;
		}

		public T Dequeue()
		{
			if (this.Length < 1)
			{
				throw new InvalidOperationException("Queue is empty");
			}
			T element = Elements[FrontIndex];
			Elements[FrontIndex] = default(T);
			Length--;
			FrontIndex = (FrontIndex + 1) % Capacity;
			return element;
		}

		protected void IncreaseCapacity()
		{
			this.Capacity++;
			this.Capacity *= 2;
			
			Queue<T> tempQueue = new Queue<T>(this.Capacity);
			
			while (this.Length > 0)
			{
				tempQueue.Enqueue(this.Dequeue());
			}
			
			this.Elements = tempQueue.Elements;
			this.Length = tempQueue.Length;
			this.FrontIndex = tempQueue.FrontIndex;
		}
	}
}
